// 生成目录
export interface IYedongHtmlParseOptions {
  renderLatex?: (text: string, clazz?: Record<string, string>, block?: boolean) => string,
  renderHighlight?: (code: string, lang: string) => string,
  renderMermaid?: (text: string) => Promise<string>
  renderPlantuml?: (text: string) => Promise<string>
}

let classAttrs = [
  'pink', 'red', 'teal', 'green', 'blue', 'yellow', 'orange', 'purple', 'white', 'gray', 'black'
]
classAttrs = classAttrs.concat(classAttrs.map(it => `bg-${it}`))
classAttrs = classAttrs.concat(classAttrs.map(it => `box-${it}`))
classAttrs = classAttrs.concat(classAttrs.map(it => `box-dotted-${it}`))
classAttrs = classAttrs.concat(classAttrs.map(it => `box-dashed-${it}`))
const classPartAttrs = ['px-', 'py-', 'p-', 'mx-', 'my-', 'm-']

async function renderMermaid(opts: IYedongHtmlParseOptions, mermaidDiagram: string, attrs = '') {
  if (!opts.renderMermaid) return ''
  const svg = await opts.renderMermaid(mermaidDiagram)
  return `<p ${attrs}>${svg}</p>`
}

async function renderPlantuml(opts: IYedongHtmlParseOptions, uml: string, attrs = '') {
  if (!opts.renderPlantuml) return ''
  const svg = await opts.renderPlantuml(uml)
  return `<p ${attrs}>${svg}</p>`
}

function renderLatex(opts: IYedongHtmlParseOptions, node: any, block = false) {
  if (!opts.renderLatex) return ''
  const attrs = transformAttrs(node.attrs)
  return opts.renderLatex(node.props.text, attrs, block)
}

export function transformAttrs(attrs?: Record<string, string>): Record<string, string> | undefined {
  if (!attrs || !Object.keys(attrs)) return undefined
  for (const key in attrs) {
    for (const classAttr of classAttrs) {
      if (key === classAttr) {
        delete attrs[key]
        if (attrs.class) {
          attrs.class += ` ${classAttr}`
        } else {
          attrs.class = classAttr
        }
        break
      }
    }
    for (const classAttr of classPartAttrs) {
      if (key.startsWith(classAttr)) {
        delete attrs[key]
        const num = Number(key.substring(classAttr.length))
        if (!num || num === 5 || num === 10 || num === 15 || num === 20) {
          if (attrs.class) {
            attrs.class += ` ${key}`
          } else {
            attrs.class = key
          }
        } else {
          // TODO 添加 style...
          if (attrs.class) {
            attrs.class += ` ${key}`
          } else {
            attrs.class = key
          }
        }
        break
      }
    }
  }
  return attrs
}

export function joinAttrs(attrs?: Record<string, string>) {
  if (!attrs) return undefined
  return Object.entries(attrs).map(([key, value]) => {
    if (value != null) {
      return `${key}="${value}"`
    } else {
      return `${key}`
    }
  }).join(' ')
}

function pad(n: number) {return '  '.repeat(n)}

// TOTO 内敛元素，不需要回车
async function renderTag(opts: IYedongHtmlParseOptions, node: any, level = 0) {
  const tag = node.tag
  if (tag === 'br' || tag === 'hr') return `<${tag}/>`
  let s = ''
  const attrs = transformAttrs(node.attrs);
  if (tag === 'img') {
    const caption = attrs?.caption ?? ''
    if (caption) delete attrs?.[caption]
    // 格式化：左边缩进空格
    const attrsStr = attrs ? ` ${joinAttrs(attrs)}` : ''
    s += `<figure>${await transformToHtml(node.children, opts, level + 1)}
    <img ${attrsStr} alt="${caption ? caption : ''}"/>`
    if (caption) s += `\n    <figcaption>${caption}</figcaption>\n`
    s += '</figure>'
  } else {
    const isInline = !!node.props?.inline
    // 格式化：左边缩进空格
    const leftStr = isInline ? '' : `\n${pad(level)}`
    const attrsStr = attrs ? ` ${joinAttrs(attrs)}` : ''
    if (node.children?.length) {
      s += `${leftStr}<${tag}${attrsStr}>${await transformToHtml(node.children, opts, level + 1)}</${tag}>`
    } else {
      s += `${leftStr}<${tag}${attrsStr}></${tag}>`
    }
  }
  return s
}

async function renderImg(opts: IYedongHtmlParseOptions, node: any, level = 0) {
  const tag = node.tag
  let s = ''
  const attrs = transformAttrs(node.attrs);
  const isInline = !!node.props?.inline
  // 格式化：左边缩进空格
  const leftStr = isInline ? '' : `\n${pad(level)}`
  const attrsStr = attrs ? ` ${joinAttrs(attrs)}` : ''
  if (node.children?.length) {
    s += `${leftStr}<${tag}${attrsStr}>${await transformToHtml(node.children, opts, level + 1)}</${tag}>`
  } else {
    s += `${leftStr}<${tag}${attrsStr}></${tag}>`
  }
  return s
}

export async function transformToHtml(ast: any[], opts: IYedongHtmlParseOptions, level = 0): Promise<string> {
  if (!ast?.length) return ''

  let s = ''
  for (let i = 0; i < ast.length; i++) {
    const node = ast[i]
    const tag = node.tag
    if (tag === 'text') {
      s += node.props.text
    } else if (tag === 'code') {
      s += opts.renderHighlight?.(node.props.text, node.attrs.lang)
    } else if (tag === 'script') {
      if (node.attrs.lang === 'mermaid') {
        s += await renderMermaid(opts, node.props.text)
      } else if (node.attrs.lang === 'plantuml') {
        s += await renderPlantuml(opts, node.props.text)
      } else {
        s += opts.renderHighlight?.(node.props.text, node.attrs.lang)
      }
    } else if (tag === 'f') {
      s += renderLatex(opts, node)
    } else if (tag === 'fb') {
      s += `\n${renderLatex(opts, node, true)}\n`
    } else {
      if (classAttrs.indexOf(tag) !== -1) {
        node.tag = 'span'
        if (node.attrs.class) {
          node.attrs.class += ` ${tag}`
        } else {
          node.attrs.class = tag
        }
        s += await renderTag(opts, node, level)
      } else {
        s += await renderTag(opts, node, level)
      }
    }
  }

  return s
}

// 1) 里面是自闭合的，A<b>BC</b>D   -> <i>A<b>BC</b>D</i>
// 2) A<b>BC  -> <i>A</i><b><i>BC</i>
// 1) A</b>BC -> <i>A</i></b><i>BC</i>
export function insertTag(text: string, newTag: string): string {
  const tagStack = []
  let length = text.length
  let s = ''
  for (let i = 0; i < length; i++) {

  }
  return `<${newTag}>${text}</${newTag}>`
}
